
#include "ArrayGenome.h"

int ArrayGenome::genomeId = 0;

double ArrayGenome::diff(const vector<double>& x) const
    {
	double sum = 0;
	for (int i=0; i<xgenome.size(); i++)
	 {
	  double dx = xgenome[i] - x[i];
	  sum += dx * dx;  
	 }
	return sqrt(sum);
    }

double ArrayGenome::diff(const ArrayGenome& other) const
    {
	double sum = 0;
	sum += other.diff(xgenome);
	return sum;
    }

double ArrayGenome::diff(const ArrayGenome* other) const
    {
	double sum = 0;
	sum += other->diff(xgenome);
	return sum;
    }

double ArrayGenome::diversity(const GAPopulation& pop)
	{
	double avgdiff = 0;
	for (int i=0; i<pop.size(); i++)
	  {
	   ArrayGenome& genome = (ArrayGenome&) pop.individual(i);
	   double diff = 0;
	   
	   for (int j=0; j<pop.size(); j++)
		{
		if (i==j)
		    continue;	
		
	        ArrayGenome& genomeJ = (ArrayGenome&) pop.individual(j);
		diff += genome.diff(genomeJ);
		}

	   diff /= (pop.size()-1);
	   avgdiff += diff;
	  }

	avgdiff /= pop.size();
	return avgdiff;
	}

void ArrayGenome::Init(GAGenome& genome)
  {
    ArrayGenome& chromosome = (ArrayGenome&) genome;
    chromosome.initialize();
  }

int ArrayGenome::Mutate(GAGenome& genome, float pmut)
  {
    ArrayGenome& chromosome = (ArrayGenome&) genome;
    int n = chromosome.mutate(pmut);
    return n;
  }

float ArrayGenome::Evaluate(GAGenome& genome)
    {
    ArrayGenome& chromosome = (ArrayGenome&) genome;

    int size = chromosome.size();
    double fitness = 900;
    for (int i=0; i<size; i++)
         {
	 double x = chromosome.getXGene(i);
	 fitness -= (x-5)*(x-5) - 10 * cos(2*3.1417*(x-5));
         }
    return (float)fitness;
    }


int ArrayGenome::Cross(const GAGenome& genome0, const GAGenome& genome1,
			   GAGenome* newgenome0, GAGenome* newgenome1)
    {
      ArrayGenome& mom = (ArrayGenome&) genome0;
      ArrayGenome& dad = (ArrayGenome&) genome1;
      ArrayGenome* sis = (ArrayGenome*) newgenome0;
      ArrayGenome* bro = (ArrayGenome*) newgenome1;

      int xgenomesize = mom.size();
      sis->newId(); 
      if (bro) {
          bro->newId();	
	}

      int momN = mom.GARandomInt(0, xgenomesize);
      sis->copyX(mom, 0, momN); // copy from mom to sis
      sis->copyX(dad, momN, xgenomesize);
      sis->invalidate();   
      if (bro) {
      	  bro->copyX(dad, 0, momN);
      	  bro->copyX(mom, momN, xgenomesize);
          bro->invalidate();   
	 }

      return 1;
    }

int ArrayGenome::initialize() 
	{
	assert(randObj);
      	for(int i = 0; i < xgenome.size(); i++)
        	{
		   int sign = randObj->GAFlipCoin(0.5) ? 1 : -1;
		   double rval = (double) sign * randObj->GARandomDouble();
		   xgenome[i] = rval;
		}

	return 0;
	}

int ArrayGenome::mutate(double p) 
    {
      int num = 0;
	
      for(int i = 0; i < xgenome.size(); i++)
        {
	if (randObj->GAFlipCoin(p) == false)
		continue;
	num ++;
	xgenome[i] += (randObj->GARandomDouble() - 0.5);
	}
	
     invalidate();   
     return num;
    }


ostream& operator<<(ostream& Ostr, const ArrayGenome& sol)
	{
	for (int i=0; i<50; i++) 
		Ostr << sol.getXGene(i) << " ";
	Ostr << endl;

	return Ostr;
	}
